package com.battcn.demo2;

import java.util.ArrayList;
import java.util.List;

/**
 * 目标对象，它知道观察它的观察者，并提供注册和删除观察者的接口
 */
class Subject {
    /**
     * 用来保存注册的观察者对象
     */
    private List<Observer> observers = new ArrayList<>();

    /**
     * 注册观察者对象
     *
     * @param observer 观察者对象
     */
    public void attach(Observer observer) {
        observers.add(observer);
    }

    /**
     * 通知所有注册的观察者对象
     */
    public void notifyObservers() {
        for (Observer observer : observers) {
            // 注意这句代码'
            observer.update(this);
        }
    }
}

/**
 * 具体的目标对象，负责把有关状态存入到相应的观察者对象，
 * 并在自己状态发生改变时，通知各个观察者
 */
class ConcreteSubject extends Subject {
    /**
     * 示意，目标对象的状态
     */
    private String subjectState;

    public String getSubjectState() {
        return subjectState;
    }

    public void change(String subjectState) {
        this.subjectState = subjectState;
        //状态发生改变，通知各个观察者
        this.notifyObservers();
    }
}

/**
 * 观察者接口，定义一个更新的接口给那些在目标发生改变的时候被通知的对象
 */
interface Observer {
    /**
     * 更新的接口
     *
     * @param subject 传入目标对象，好获取相应的目标对象的状态
     */
    void update(Subject subject);
}

/**
 * 具体观察者对象，实现更新的方法，使自身的状态和目标的状态保持一致
 */
class ConcreteObserver implements Observer {
    /**
     * 示意，观者者的状态
     */
    private String observerState;

    @Override
    public void update(Subject subject) {
        //具体的更新实现
        //这里可能需要更新观察者的状态，使其与目标的状态保持一致
        observerState = ((ConcreteSubject) subject).getSubjectState();
        System.out.println("接收到：" + observerState);
    }
}


/**
 * 拉模型
 *
 * @author Levin
 * @date 2017-12-11.
 */
public class PullClient {

    public static void main(String[] args) {
        //创建主题对象
        ConcreteSubject subject = new ConcreteSubject();
        //创建观察者对象
        Observer observer = new ConcreteObserver();
        //将观察者对象登记到主题对象上
        subject.attach(observer);
        //改变主题对象的状态
        subject.change("pull state");
    }

}
